// 自定义promise  
((window) => {

  // 定义状态值常量
  const PENDING = 'pending';
  const FULFILLED = 'fulfilled';
  const REJECTED = 'rejected';

  /**
   * 构造函数   @param 给参数命名的意思
   * @param  excutor 执行器函数
   */

  /* 
  promise对象内部要存储哪些信息?
    1. 状态: pending/fulfilled/rejected  ==> state
    2. 结果数据: undefined/value/reason  ==> data
    3. 保存待处理回调的数组: [{resolved () {}, rejected () {}}, {resolved () {}, rejected () {}}] => callbacks
 
    在构造函数中, 会立即同步调用执行器函数, 并传入resolve和reject 两个函数

    resolve函数
      参数: value
      作用: 将promise的状态改为resolved, 将value保存到data
    reject函数
      参数: reason
      作用: 将promise的状态改为rejected, 将reason保存到data
  */

  function Promise (excutor) {
    // 初始化三个属性
    // 1. 状态 pending/fulfilled/rejected  ==> state
    this.state = PENDING
    // 2. 结果数据  undefined/value/reason  ==> data
    this.data = undefined
    // 3. 保存待处理回调的数组: [{resolved () {}, rejected () {}}, {resolved () {}, rejected () {}}] => callbacks
    this.callbacks = [];
    // 声明一个变量 让内部的变量可以指向state   
    // 也可以把resolve改成箭头函数 可以用this指向state
    const self = this;


    /* 
    resolve函数
    参数: value
    作用: 将promise的状态改为resolved, 将value保存到data
   */
    function resolve (value) {
      // 只有当前状态为pendding, 才向下处理
      if (self.state !== PENDING) return
      // 改状态为成功的
      self.state = FULFILLED
      // 保存数据
      self.data = value
      // 异步执行callbacks中所有成功的回调  callbacks里保存待处理回调的数组
      // 我们没办法直接向微队列中添加回调 => 只能用宏队列了 setTimeout
      setTimeout(() => {
        self.callbacks.forEach(callbackObj => callbackObj.resolved(value))
      }, 0)
    }

    /* 
    reject函数
    参数: reason
    作用: 将promise的状态改为rejected, 将reason保存到data
    */
    function reject (reason) {
      // 只有当前状态为pendding, 才向下处理
      if (self.state !== PENDING) return

      // 改状态为失败的
      self.state = REJECTED
      // 保存数据
      self.data = reason
      // 异步执行callbacks中所有失败的回调  callbacks里保存待处理回调的数组
      // 我们没办法直接向微队列中添加回调 => 只能用宏队列了 setTimeout
      setTimeout(() => {
        self.callbacks.forEach(callbackObj => callbackObj.rejected(reason))
      }, 0)
    }


    // 捕获执行器抛出的错误
    try {
      /*  在构造函数中, 会立即同步调用执行器函数, 并传入resolve和reject 两个函数 */
      excutor(resolve, reject);
    } catch (error) {
      // 将当前promise变为rejected, reason为error
      reject(error)
    }
  }

  /**
   * 指定成功和失败的回调, 并返回一个新的promise  都放到Promise的原型对象上
   * @param {*} onResolved 成功的回调 => 用于得到成功的value
   * @param {*} onRejected 失败的回调 => 用于得到失败的reason
   */

  /* 
 then返回的promise的结果由什么决定
  简单表达: 由then指定的回调执行的结果决定
    返回promise  ==> 得到并改为它的状态
    返回非promise  ==> 变为成功状态
    抛出错误   ==> try---catch  => 变为失败状态
*/

  // 成功的回调
  Promise.prototype.then = function (onResolved, onRejected) {
    const self = this


    // 返回一个新的promise
    return new Promise((resolve, reject) => {
      if (self.state === FULFILLED) { // 如果当前promise是成功的, 异步执行成功的回调
        setTimeout(() => {
          try {
            const result = onResolved(self.data)
            if (result instanceof Promise) { // 情况1: 返回promise  ==> 得到并改为它的状态
              result.then(
                value => resolve(value),
                reason => reject(reason)
              )
            } else { // 情况2: 返回非promise  ==> 变为成功状态
              resolve(result)
            }
          } catch (error) { // 情况3: 抛出错误   ==> try---catch  => 变为失败状态
            reject(error)
          }
        }, 0)
      } else if (self.state === REJECTED) { // 如果当前promise是失败的, 异步执行失败的回调
        setTimeout(() => {
          try {
            const result = onRejected(self.data)
            if (result instanceof Promise) { // 情况1: 返回promise  ==> 得到并改为它的状态
              result.then(
                value => resolve(value),
                reason => reject(reason)
              )
            } else { // 情况2: 返回非promise  ==> 变为成功状态
              resolve(result)
            }
          } catch (error) { // 情况3: 抛出错误   ==> try---catch  => 变为失败状态
            reject(error)
          }
        }, 0)
      } else { // 如果当前promise是pending, 保存成功和失败的回调
        this.callbacks.push({
          // 问题: 不会根据成功/失败回调执行的结果个改变返回的promise的状态
          // resolve: onResolved,
          resolved: (value) => {
            console.log('my onResolved')
            try {
              const result = onResolved(self.data)
              if (result instanceof Promise) { // 情况1: 返回promise  ==> 得到并改为它的状态
                result.then(
                  value => resolve(value),
                  reason => reject(reason)
                )
              } else { // 情况2: 返回非promise  ==> 变为成功状态
                resolve(result)
              }
            } catch (error) { // 情况3: 抛出错误   ==> try---catch  => 变为失败状态
              reject(error)
            }
          },
          rejected: (reason) => {
            console.log('my onRejected')
            try {
              const result = onRejected(reason)
              if (result instanceof Promise) {
                result.then(
                  value => { resolve(value) },
                  reason => reject(reason)
                )
              } else {
                resolve(result)
              }
            } catch (error) {
              reject(error)
            }
          }
        })
      }
    })
  }

  // 失败的回调
  Promise.prototype.catch = function (onRejected) { }

  /**
  *  返回一个成功的promise, value为指定的value
  * @param {*} value 
  */
  Promise.resolve = function (value) { }

  /**
   *  返回一个失败的promise, reason为指定的reason
   * @param {*} reason
   */
  Promise.reject = function (reason) { }

  /**
   * 返回一个promise, 如果promises都成功, 才成功   成功的value为所有value组成的数组, 只要有一个失败, 那它就失败了
   * @param {*} promises  
   */
  Promise.all = function (promises) { }

  /**
 * 返回一个promise, 由第一个完成的promie来决定它的结果
 * @param {*} promises 
 */
  Promise.race = function (promises) { }

  /**
   * 返回一个promise, 当所有promise都完成时它就成功, value值为所有promise的value或reason组成的数组
   * @param {*} promises 
   */
  Promise.allSettled = function (promises) { }

  // 向外暴露自定义的Promise
  window.Promise = Promise
})(window)
